﻿#include "DlgCube.h"

#include <QMouseEvent>
#include <math.h>
#include <QPen>
#include <QPainter>
#include <QTime>

DlgCube::DlgCube(int width, int height, QWidget *parent) :
    QOpenGLWidget(parent),
    geometries(0),
    texture(0),
    angularSpeed(0)
{
    this->setFixedSize(width, height);
}

DlgCube::~DlgCube()
{
    // Make sure the context is current when deleting the texture
    // and the buffers.
    makeCurrent();
    delete texture;
    delete geometries;
    doneCurrent();
}

void DlgCube::mousePressEvent(QMouseEvent *e)
{
    // Save mouse press position
    mousePressPosition = QVector2D(e->localPos());
}

void DlgCube::mouseMoveEvent(QMouseEvent *e)
{
    //qDebug()<<e->pos();
    // Mouse release position - mouse press position
    QVector2D diff = QVector2D(e->localPos()) - mousePressPosition;

    // Rotation axis is perpendicular to the mouse position difference
    // vector
    QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();

    // Accelerate angular speed relative to the length of the mouse sweep
    qreal acc = diff.length() / 100.0;

    // Calculate new rotation axis as weighted sum
    rotationAxis = (rotationAxis * angularSpeed + n * acc).normalized();

    // Increase angular speed
    angularSpeed += acc;

    mousePressPosition = QVector2D(e->localPos());
}

void DlgCube::timerEvent(QTimerEvent *)
{
    // Decrease angular speed (friction)
    angularSpeed *= 0.95;

    // Stop rotation when speed goes below threshold
    if (angularSpeed < 0.01) {
        angularSpeed = 0.0;
    } else {
        // Update rotation
        rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angularSpeed) * rotation;

        // Request an update
        update();
    }
}

void DlgCube::initializeGL()
{
    initializeOpenGLFunctions();
    //球 后 widget 的背景色
//    glClearColor(1, 1, 1, 0);

    initShaders();
    initTextures();
    // Enable depth buffer
    glEnable(GL_DEPTH_TEST);

    // Enable back face culling
    glEnable(GL_CULL_FACE);

    //////////////////////
//    glEnable(GL_LINE_SMOOTH);
//    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
//    glEnable(GL_BLEND);
//    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    ///////////

    geometries = new GeometryEngine;
    // Use QBasicTimer because its faster than QTimer
    timer.start(12, this);
}

void DlgCube::initShaders()
{
    // Compile vertex shader
    if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vshader.glsl"))
        close();

    // Compile fragment shader
    if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fshader.glsl"))
        close();

    // Link shader pipeline
    if (!program.link())
        close();

    // Bind shader pipeline for use
    if (!program.bind())
        close();
}

void DlgCube::initTextures()
{
    // Load cube.png image
    texture = new QOpenGLTexture(myImage.mirrored());

    // Set nearest filtering mode for texture minification
    texture->setMinificationFilter(QOpenGLTexture::Nearest);

    // Set bilinear filtering mode for texture magnification
    texture->setMagnificationFilter(QOpenGLTexture::Linear);

    // Wrap texture coordinates by repeating
    // f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2)
    texture->setWrapMode(QOpenGLTexture::Repeat);
}

void DlgCube::resizeGL(int w, int h)
{
    // Calculate aspect ratio
    qreal aspect = qreal(w) / qreal(h ? h : 1);

    // Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
    //fov 可以调节大小
    const qreal zNear = 2.5, zFar = 7.0, fov = 45.0;

    // Reset projection
    projection.setToIdentity();

    // Set perspective projection
    projection.perspective(fov, aspect, zNear, zFar);
}

void DlgCube::paintGL()
{
    // Clear color and depth buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    texture->bind();
    // Calculate model view transformation
    QMatrix4x4 matrix;
    matrix.translate(0.0, 0.0, -5.0);
    matrix.rotate(rotation);

    // Set modelview-projection matrix
    program.setUniformValue("mvp_matrix", projection * matrix);
    // Use texture unit 0 which contains cube.png
    program.setUniformValue("texture", 0);

    // Draw cube geometry
    geometries->drawCubeGeometry(&program);
}

void DlgCube::InitCube()
{
    m_which_color = 0;

    tip_1.clear();
    tip_2.clear();
    tip_3.clear();
    tip_4.clear();
    tip_5.clear();
    tip_6.clear();

    tip_1.push_back("<静夜思>");
    tip_1.push_back("床前明月光");
    tip_1.push_back("疑是地上霜");
    tip_1.push_back("举头望明月");
    tip_1.push_back("低头思故乡");

    tip_2.push_back("<江雪>");
    tip_2.push_back("千山鸟飞绝");
    tip_2.push_back("万径人踪灭");
    tip_2.push_back("孤舟蓑笠翁");
    tip_2.push_back("独钓寒江雪");

    tip_3.push_back("<闻乐天授江州司马>");
    tip_3.push_back("残灯无焰影幢幢");
    tip_3.push_back("此夕闻君谪九江");
    tip_3.push_back("垂死病中惊坐起");
    tip_3.push_back("暗风吹雨入寒窗");

    tip_4.push_back("问世间情是何物");
    tip_4.push_back("直教生死相许");
    tip_4.push_back("天南地北双飞客");
    tip_4.push_back("老翅几回寒暑");
    tip_4.push_back("欢乐趣");

    tip_5.push_back("离别苦");
    tip_5.push_back("就中更有痴儿女");
    tip_5.push_back("君应有语");

    tip_6.push_back("渺万里层云，千山暮雪，只影向谁去?");
    //merge
    QString str = QString(":image/edge.png");
    QImage resultImg(str);
    //
    QPainter painter;
    painter.begin(&resultImg);
    //在新区域画图
    painter.drawImage(  0,   0, Text_To_Image(0));
    painter.drawImage(396,   0, Text_To_Image(1));
    painter.drawImage(792,   0, Text_To_Image(2));
    painter.drawImage(  0, 400, Text_To_Image(3));
    painter.drawImage(396, 400, Text_To_Image(4));
    painter.drawImage(792, 400, Text_To_Image(5));
    painter.end();
    QString strResultImg = QString("./tiledball.png");
    resultImg.save(strResultImg);
    myImage = resultImg;
}

void DlgCube::MoveLittle()
{
    //move 初始位置露出一个角
    QVector2D diff = QVector2D(QPoint(180,180));
    QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();
    qreal acc = diff.length() / 100.0;
    rotationAxis = (rotationAxis * angularSpeed + n * acc).normalized();
    angularSpeed += acc;
}

QImage DlgCube::Text_To_Image(int count)
{
    QVector <QString> tip;
    QImage img;
    switch(count)
    {
    case 0:tip = tip_1; img.load(":image/11.png");break;
    case 1:tip = tip_2; img.load(":image/22.png");break;
    case 2:tip = tip_3; img.load(":image/33.png");break;
    case 3:tip = tip_4; img.load(":image/44.png");break;
    case 4:tip = tip_5; img.load(":image/55.png");break;
    case 5:tip = tip_6; img.load(":image/66.png");break;
    default:break;
    }
    QPainter painter;
    painter.begin(&img);

    QFont font;
    font.setBold(true);

    int tip_size = tip.size()>8?8:tip.size();
    for(int i=0;i<tip_size;i++)
    {
        switch (m_which_color%2)
        {
        case 0:font.setFamily("Noto Sans S Chinese Thin");break;
        case 1:font.setFamily("Noto Sans S Chinese Bold");break;
        default:break;
        }
        font.setPixelSize(random_fontpixsize(tip[i].length()));
        painter.setFont(font);
        QPen pen = random_Color();
        painter.setPen(pen);
        //左右各留20px
        int x = 20 + qrand()%((360 - tip[i].length()*font.pixelSize())+1);
        if(x<0)
            x = 5;
        //y会在实际图上向下偏移10个坐标
        int y = 380/tip_size*i + qrand()%((380/tip_size - font.pixelSize())+1);
        painter.drawText(QRect(x, y, 380,380), Qt::AlignLeft|Qt::AlignTop,tip[i]);
    }

    painter.end();
    return img;
}

QPen DlgCube::random_Color()
{
    QPen pen;
    switch (m_which_color % 4) {
    case 0:pen.setColor(QColor(151,255,244));
        break;
    case 1:pen.setColor(QColor(255,195,109));
        break;
    case 2:pen.setColor(QColor(124,204,255));
        break;
    case 3:pen.setColor(QColor(255,255,255));
        break;
    default:
        break;
    }
    m_which_color++;
    return pen;
}

int DlgCube::random_fontpixsize(int fontlen)
{
    if(0 == fontlen)
        return 1;
    int size = (380 / fontlen / 2) + qrand()%(380 / fontlen / 2);
    //字体大小 25<size<38
    if (size > 38)
        size = 33 + qrand() % 6;

    if(size < 25)
        size = 25 + qrand() % 6;

    return  size;
}

